#pragma once
/*
日志器模块或者说写入方式模块
日志器是直接暴露给用户的
功能:完成用户交给日志器的具体日志打印工作
设计思想:
为此站在用户的角度来说就是
我只要将日志消息传递给日志器，日志器就能帮助我们完成日志的输出
因此日志器要提供一些接口来供用户传入日志消息
而站在日志器的角度来说，我通过上诉接口获取到了用户的日志信息，日志器要做的工作就是
根据用户传进来的日志信息封装一个日志对象
然后利用格式化类对象格式化日志对象
然后再使用一个落地接口完成最终落地！

一个日志器的落地方向可能不止一种，为此我们需要一个容器来保存落地方向
日志器也需要知道如何格式化对象,为此他需要一个格式化对象
多线程情况下，有可能多个线程使用同一个日志器对同一个落地方向进行输出，会造成线程安全，需要一把锁
日治器也需要一个限制等级来维护日志器正对那些等级的日志进行实际落地，那些日志不进行输出;
日志器也需要一个名字来标识唯一日志器

如果具体细分的话，日志器分为:同步日志器、异步日志器
为此为了方便管理日志器，可以采用继承的设计层次
*/
#include "util.hpp"
#include "level.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <mutex>
#include <stdarg.h>
#include <unordered_map>
namespace LoggerSpace
{
    // 先抽象出一个基类日志器
    class Logger
    {
    public:
        virtual ~Logger() {}
        enum class LoggerType
        {
            LOGGER_SYNC, // 同步日志器
            LOGGER_ASYNC // 异步日志器
        };

        // 提供日志器基本功能
    public:
        Logger(const LoggerSpace::Formater &fmt, const std::vector<std::shared_ptr<LoggerSpace::Sink>> &sinks, const std::string name,
               LoggerSpace::LogLevel lev = LogLevel::DEBUG, LoggerType type = LoggerType::LOGGER_SYNC)
            : _fmter(fmt), _sinks(sinks), _levelLimits(lev), _mux(), _loggerName(name)
        {
            if (_sinks.empty())
                _sinks.push_back(std::make_shared<StdoutSink>());
        }
        const std::string &name()
        {
            return _loggerName;
        }
        // 站在用户的角度，是我只要想给接口提供日志信息就能完成debug等级的输出
        void debug(const std::string &fileName, size_t line, const char *fmat, ...)
        {
            // 站在日志器的角度来说，我收到了用户的日志信息，我需要将其加工成日志对象，然后格式化，然后完成实际落地
            // 0、先判断是否大于>=当前限制等级
            // 1、提取出日志消息主体;
            // 2、构造日志对象
            // 3、格式化
            va_list ap;
            va_start(ap, fmat);
            std::string str;
            // 完成0~3的工作
            if (!forwardRoll(fileName, line, LogLevel::DEBUG, str, fmat, ap))
            {
                va_end(ap);
                return;
            }
            va_end(ap);
            // 4、实际落地
            log(str);
        }
        void info(const std::string &fileName, size_t line, const char *fmat, ...)
        {

            va_list ap;
            va_start(ap, fmat);
            std::string str;
            // 完成0~3的工作
            if (!forwardRoll(fileName, line, LogLevel::INFO, str, fmat, ap))
            {
                va_end(ap);
                return;
            }
            va_end(ap);
            // 4、实际落地
            log(str);
        }
        void warning(const std::string &fileName, size_t line, const char *fmat, ...)
        {
            va_list ap;
            va_start(ap, fmat);
            std::string str;
            // 完成0~3的工作
            if (!forwardRoll(fileName, line, LogLevel::WARNING, str, fmat, ap))
            {
                va_end(ap);
                return;
            }
            va_end(ap);
            // 4、实际落地
            log(str);
        }
        void error(const std::string &fileName, size_t line, const char *fmat, ...)
        {
            va_list ap;
            va_start(ap, fmat);
            std::string str;
            // 完成0~3的工作
            if (!forwardRoll(fileName, line, LogLevel::Err, str, fmat, ap))
            {
                va_end(ap);
                return;
            }
            va_end(ap);
            // 4、实际落地
            log(str);
        }
        void fatal(const std::string &fileName, size_t line, const char *fmat, ...)
        {
            va_list ap;
            va_start(ap, fmat);
            std::string str;
            // 完成0~3的工作
            if (!forwardRoll(fileName, line, LogLevel::FATAL, str, fmat, ap))
            {
                va_end(ap);
                return;
            }
            va_end(ap);
            // 4、实际落地
            log(str);
        }
        void unknown(const std::string &fileName, size_t line, const char *fmat, ...)
        {
            va_list ap;
            va_start(ap, fmat);
            std::string str;
            // 完成0~3的工作
            if (!forwardRoll(fileName, line, LogLevel::UNKNOWN, str, fmat, ap))
            {
                va_end(ap);
                return;
            }
            va_end(ap);
            // 4、实际落地
            log(str);
        }

    private:
        bool forwardRoll(const std::string &fileName, size_t line, LogLevel lev, std::string &outBuffer, const char *fmat, va_list &ap)
        {
            if (lev < _levelLimits)
                return false;
            // 提取有效载荷消息
            char buffer[4096];
            vsnprintf(buffer, sizeof(buffer), fmat, ap);
            // 构建日志对象
            LogMes mes(fileName, line, lev, _loggerName, buffer);
            // 格式化
            outBuffer = _fmter.format(mes);
            return true;
        }

    protected:
        // 完成实际落地
        // 根据不同类型日志器完成不同的落地操作
        virtual void log(const std::string &str) = 0;
        LoggerSpace::Formater _fmter;                           // 用来记录当前日志器的格式化格式
        std::vector<std::shared_ptr<LoggerSpace::Sink>> _sinks; // 记录实际落地方向
        std::mutex _mux;                                    // 保护日志器的线程安全
        LoggerSpace::LogLevel _levelLimits;                     // 日志限制输出等级
        std::string _loggerName;                            // 日志器名称
        LoggerType _type;
    };

    // 具体派生出一个同步日志器
    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const LoggerSpace::Formater &fmt, const std::vector<std::shared_ptr<LoggerSpace::Sink>> &sinks, const std::string name,
                   LoggerSpace::LogLevel lev = LogLevel::DEBUG) : Logger(fmt, sinks, name, lev, LoggerType::LOGGER_SYNC) {}
        virtual void log(const std::string &str) override
        {
            std::lock_guard<std::mutex> locker(_mux);
            for (auto &e : _sinks)
                e->outLog(str.c_str(), str.length());
        }
    };
    // 具体派生出一个异步日器
    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const LoggerSpace::Formater &fmt, const std::vector<std::shared_ptr<LoggerSpace::Sink>> &sinks, const std::string name,
                    LoggerSpace::LogLevel lev = LogLevel::DEBUG, bool safe = true) : Logger(fmt, sinks, name, lev, LoggerType::LOGGER_SYNC), _looper(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), safe)
        {
        }
        virtual void log(const std::string &str) override
        {
            _looper.push(str.c_str(), str.size());
        }

    private:
        void realLog(Buffer &bf)
        {
            for (auto &e : _sinks)
                e->outLog(bf.begin(), bf.AbleReadSize());
            bf.moveRead(bf.AbleReadSize());
        }
        LoggerSpace::AsyncLooper _looper;
    };

    // 创建日志器所需要的零件
    class Builder
    {
    public:
        virtual ~Builder() {}
        void buildLoggerName(const std::string name)
        {
            _loggerName = name;
        }
        void buildLoggerType(Logger::LoggerType type = Logger::LoggerType::LOGGER_SYNC)
        {
            _type = type;
        }
        void buildFormater(const std::string &fmt = "")
        {
            if (fmt == "")
                _fmt = Formater();
            else
                _fmt = Formater(fmt);
        }
        void buildLevelLimits(LogLevel lev = LogLevel::DEBUG)
        {
            _levelLimits = lev;
        }
        void EableSafe(bool flag)
        {
            _safe = flag;
        }
        template <class T, class... Args>
        void buildSink(Args... args)
        {
            _sinks.push_back(SinkFactory::createSink<T>(args...));
        }
        // 根据零件组合一个具体对象
        virtual std::shared_ptr<Logger> build() = 0;

    protected:
        bool _safe;
        std::string _loggerName;
        Logger::LoggerType _type;
        Formater _fmt;
        LoggerSpace::LogLevel _levelLimits;
        std::vector<std::shared_ptr<LoggerSpace::Sink>> _sinks;
    };

    // 局部日志器建造
    class LocalLoggerBuilder : public Builder
    {
    public:
        virtual std::shared_ptr<Logger> build() override
        {
            std::shared_ptr<std::vector<std::shared_ptr<LoggerSpace::Sink>>> sp(&_sinks, [](std::vector<std::shared_ptr<LoggerSpace::Sink>> *ptr) -> void
                                                                            { ptr->clear(); });
            std::shared_ptr<Logger> it(nullptr);
            if (_type == Logger::LoggerType::LOGGER_SYNC)
                it = std::make_shared<SyncLogger>(_fmt, _sinks, _loggerName, _levelLimits);
            else
                it = std::make_shared<AsyncLogger>(_fmt, _sinks, _loggerName, _levelLimits, _safe);
            _safe = true;
            _loggerName.clear();
            return it;
        }
    };
    /*
   创建一个日志器管理类:
   该类提供的作用:
   1、管理已创建的日志器
   2、可以同通过该管理器在全局任意地方根据日志器名称获取日志器
   3、该管理器默认提供一个标标准输出的日志器
   4、该管理器为单例对象，全局只有一个管理器对象
   提供接口:
       getInstance();//获取日志管理器对象
       addLogger();//添加日志器
       isExists();//日志器是否存在
       getLogger();//获取日志器
       getRootLogger();//获取默认日志器
   管理成员;
   unordered_map<string ,shared_ptr<Logger>> _loggers;
   mutex保证日志管理器对象的线程安全
   默认日志器对象 (同步标输出)
   */
    class loggerManager
    {
    public:
        static loggerManager &getInstance()
        {
            static loggerManager lo;
            return lo;
        }
        void addLogger(std::shared_ptr<Logger> &ptr)
        {
            if (isExists(ptr->name()))
                return;
            _loggers[ptr->name()] = ptr;
        }
        bool isExists(const std::string &name)
        {
            auto it = _loggers.find(name);
            if (it == _loggers.end())
                return false;
            return true;
        }
        std::shared_ptr<Logger> getLogger(const std::string &name)
        {
            if (isExists(name))
                return _loggers[name];
            return nullptr;
        }
        std::shared_ptr<Logger> getRootLogger()
        {
            return _root;
        }

    private:
        loggerManager()
        {
            LocalLoggerBuilder lo;
            lo.buildFormater();
            lo.buildLevelLimits();
            lo.buildLoggerName("root");
            lo.buildLoggerType();
            lo.buildSink<StdoutSink>();
            _root = lo.build();
            std::string name("root");
            _loggers[name] = _root;
        }
        loggerManager(const loggerManager &) = delete;
        loggerManager(loggerManager &&) = delete;
        std::unordered_map<std::string, std::shared_ptr<Logger>> _loggers;
        std::mutex _mux;
        std::shared_ptr<Logger> _root; // 默认日志器
    };
    // 全局日志器建造者//改日志器建造者是配合日志器管理对象来使用的
    // 与局部日志器建造者的唯一区别就是多了一步将构建出来的日志器添加进日志器管理对象的步骤
    // 省去了用户需要手动添加的过程
    class GobalLoggerBuilder : public Builder
    {
    public:
        virtual std::shared_ptr<Logger> build() override
        {
            std::shared_ptr<std::vector<std::shared_ptr<LoggerSpace::Sink>>> sp(&_sinks, [](std::vector<std::shared_ptr<LoggerSpace::Sink>> *ptr) -> void
                                                                            { ptr->clear(); });
            std::shared_ptr<Logger> it(nullptr);
            if (_type == Logger::LoggerType::LOGGER_SYNC)
                it = std::make_shared<SyncLogger>(_fmt, _sinks, _loggerName, _levelLimits);
            else
                it = std::make_shared<AsyncLogger>(_fmt, _sinks, _loggerName, _levelLimits,_safe);
            //_sinks.clear();
            loggerManager::getInstance().addLogger(it);
            _safe = true;
            _loggerName.clear();
            return it;
        }
    };
}